﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BaseEfRepository.cs" company="DST Nexdox">
//   Copyright (c) DST Nexdox. All rights reserved.
// </copyright>
// <summary>
//   Defines the BaseEfRepository type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace EFRepository
{
  using System;
  using System.Collections.Generic;
  using System.Data.Entity;
  using System.Linq;
  using Repository;

  public abstract class BaseEfRepository<T> : IRepository<T>
    where T : class
  {
    private readonly DbContext dataDbContext;

    private readonly DbSet<T> databaseSet;

    protected BaseEfRepository(DbContext dataDbContext)
    {
      this.dataDbContext = dataDbContext;
      this.databaseSet = dataDbContext.Set<T>();
      this.BatchSize = 1000;
    }

    public Int32 BatchSize { get; set; }

    public IQueryable<T> Entities
    {
      get
      {
        return this.databaseSet;
      }
    }

    public void Update(T entity)
    {
      this.databaseSet.Attach(entity);
      this.dataDbContext.Entry(entity).State = EntityState.Modified;
      this.Save();
    }

    public T Create(T entity)
    {
      var added = this.databaseSet.Add(entity);
      this.Save();
      return added;
    }

    public void Create(IEnumerable<T> collection)
    {
      Boolean originalAutoDetectChangesPreference = this.dataDbContext.Configuration.AutoDetectChangesEnabled;

      try
      {
        this.dataDbContext.Configuration.AutoDetectChangesEnabled = false;

        Int32 numberOfItemsInSet = 0;

        foreach (T entity in collection)
        {
          this.databaseSet.Add(entity);
          numberOfItemsInSet++;

          if (numberOfItemsInSet == BatchSize)
          {
            this.Save();
            numberOfItemsInSet = 0;
          }
        }

        if (numberOfItemsInSet > 0)
        {
          this.Save();
        }
      }
      finally
      {
        this.dataDbContext.Configuration.AutoDetectChangesEnabled = originalAutoDetectChangesPreference;
      }
    }

    public void Delete(T entity)
    {
      this.databaseSet.Remove(entity);
      this.Save();
    }

    public void Delete(IEnumerable<T> entities)
    {
      Boolean originalAutoDetectChangesPreference = this.dataDbContext.Configuration.AutoDetectChangesEnabled;
      try
      {
        this.dataDbContext.Configuration.AutoDetectChangesEnabled = false;

        Int32 numberOfItemsInSet = 0;

        foreach (T entity in entities)
        {
          this.databaseSet.Remove(entity);
          numberOfItemsInSet++;

          if (numberOfItemsInSet == BatchSize)
          {
            this.Save();
            numberOfItemsInSet = 0;
          }
        }

        if (numberOfItemsInSet > 0)
        {
          this.Save();
        }
      }
      finally
      {
        this.dataDbContext.Configuration.AutoDetectChangesEnabled = originalAutoDetectChangesPreference;
      }
    }

    public void Dispose()
    {
      if (this.dataDbContext != null)
      {
       this.dataDbContext.Dispose(); 
      }
    }

    protected void Save()
    {
      this.dataDbContext.SaveChanges();
    }
  }
}
